
local Request = import("./Request.lua");
local Response = import("./Response.lua");
local Context = import("./Context.lua");
local Router = import("./Router.lua");
local Cors = import("./Middleware/Cors.lua");

local WebServer = commonlib.inherit(commonlib.Server);
WebServer:Property("StaticDirectory");         -- 静态文件目录
WebServer:Property("ControllerDirectory");     -- 控制器目录
WebServer:Property("Router");                  -- 路由

local function DefaultHandle(ctx)
    ctx:Send(nil, 204);
end

function WebServer:ctor()
    self.middlewares = {};
    self.virtual_directory = {};

    self:SetRouter(Router:new():Init());
    self:UseCors();
end

-- 添加虚拟目录 静态文件目录
function WebServer:AddVirtualDirectory(path, directory)
    self.virtual_directory[path] = directory;
end

function WebServer:HandleStaticFile(ctx)
    local method = ctx:GetMethod();
    local path = ctx:GetPath();
    local filepath = nil;

    for static_path, dir in pairs(self.virtual_directory) do
        if (string.find(path, static_path, 1, true)) then
            filepath = dir .. string.sub(path, string.len(static_path) + 1);
        end
    end

    if (not filepath) then return end
    ctx:SendFile(filepath);
end

function WebServer:HandleController(ctx)
    local controller_directory = self:GetControllerDirectory();
    if (not controller_directory) then return end

    local function controller_handle(controller_filename, method_name)
        controller_filename = string.gsub(controller_filename, "[\\/]*$", "");
        if (string.sub(controller_filename, #controller_filename - 3) ~= ".lua") then
            controller_filename = controller_filename .. ".lua";
        end
        if (commonlib.IsExistFile(controller_filename)) then
            local controller = import(controller_filename);
            if (type(controller) == "table") then
                if (type(controller[method]) == "function") then
                    return (controller[method])(ctx);
                end
            end
            if (type(controller) == "function") then
                controller()
            end
        end
    end
    controller_handle(commonlib.FormatPath(controller_directory .. path), string.lower(ctx:GetMethod()));
    controller_handle(commonlib.FormatPath(controller_directory .. commonlib.GetDirectory(path)), commonlib.GetFileName(path));
end

function WebServer:Handle(socket, http_text)
    local request = Request:new():Init(http_text);
    local response = Response:new():Init(request, socket);
    local ctx = Context:new():Init(request, response);

    --print("================http request================")
    --print(http_text);

	-- 优先处理静态文件
    self:HandleStaticFile(ctx);
    -- 出来API
    local middlewares = self.middlewares;
    local function handle(ctx, index)
        if (ctx:IsFinished()) then return end

        index = index or 1;
        if (index > #middlewares) then
            -- 中间件处理完成 
            -- 执行路由逻辑
            if (not ctx:IsFinished()) then self:GetRouter():Handle(ctx) end
            -- 执行控制器逻辑
            if (not ctx:IsFinished()) then self:HandleController(ctx) end 
            -- 默认处理
            if (not ctx:IsFinished()) then ctx:DoNotFound() end 
        else
            -- 执行中间件逻辑
            local middleware = middlewares[index];
            local isExecNext = false;
            local function next() 
                if (isExecNext) then return end
                isExecNext = true;
                handle(ctx, index + 1)
            end
            if (type(middleware) == "function") then
                middleware(ctx, next);
            elseif (type(middleware) == "table" and type(middleware.Handle) == "function") then
                middleware.Handle(middleware, ctx, next);
            end
            next();
        end
    end
    handle(ctx);
end

-- 注册中间件
function WebServer:Use(callback)
    if (type(callback) == "table" and type(callback.Handle) == "function") then table.insert(self.middlewares, function(ctx, next) callback:Handle(ctx, next) end) end
    if (type(callback) == "function") then table.insert(self.middlewares, callback) end 
    return self;
end

-- Cors 中间件
function WebServer:UseCors(options)
    if (self.__cors_callback__) then return self end 

    local __cros__ = Cors:new():Init(options);
    self.__cors_callback__ = function(ctx, next) __cros__:Handle(ctx, next) end
    self:Use(self.__cors_callback__);
    
    return self;
end

-- 注册路由
function WebServer:Get(path, callback)
    self:GetRouter():Router(path, callback, "GET");
end

function WebServer:Post(path, callback)
    self:GetRouter():Router(path, callback, "POST");
end

function WebServer:Del(path, callback)
    self:GetRouter():Router(path, callback, "DELETE");
end

function WebServer:All(path, callback)
    self:GetRouter():Router(path, callback, "ALL");
end

function WebServer:Router(path, callback, description)
    self:GetRouter():Router(path, callback, description);
end

return WebServer;

-- https://www.cnblogs.com/jpfss/p/10984966.html